package my.jieh.tips.io.file;

import java.net.*;
import java.io.*;

/**
 * <p>Title: run a jar <u>from</u> anywhere in the world</p>
 * <p>Description: java -jar runajar.jar <url or path of the jar to run> <arguments>
 *             or: runajar <url or path of the jar to run> <arguments></p>
 * <p>Company: Borland</p>
 * @author vpatryshev
 * @version 1.0
 */

public class Runajar {

  static final int BLOCK_SIZE = 65500; // bytes
  static byte[] buf = new byte[BLOCK_SIZE];
  static final int SLEEP_UNIT = 333; // msec
  static final String TMP_DIR = "/tmp/runjar";

  public static void main(String[] args) {
    try {
      if (args.length > 0) {
        String urlstring = args[0]; // jar url string
        File here = new File(".");
        File localcopy = new File(urlstring);

        if (!localcopy.exists()) {
          URL url = new URL(urlstring);
          String filename = urlstring.substring(urlstring.lastIndexOf('/') + 1); // jar name
          File root = new File(here.getAbsolutePath()); // is not it something?
          while (root.getParent() != null &&
                 root.getParent() != root.getCanonicalPath()) {
            root = new File(root.getParent()); // that's the way to find the root
          }
          File tmpdir = new File(root, TMP_DIR);

          if (!tmpdir.exists()) {
            tmpdir.mkdirs();

          }
          localcopy = new File(tmpdir, filename); // local copy of the jar
          InputStream is = new BufferedInputStream(url.openStream());
          OutputStream os = new BufferedOutputStream(new FileOutputStream(
              localcopy));
          pipe(is, os, true);
          os.close();
          is.close();
        }
        String javaexec = System.getProperty("java.home") + File.separator +
            "bin" + File.separator +
            "java";
        String cmd = javaexec + " -jar " + localcopy.getAbsolutePath();

        for (int i = 1; i < args.length; i++) {
          cmd += " " + args[i] + " ";
        }
        Process process = Runtime.getRuntime().exec(cmd, null, here);
        int result = 0;

        for (boolean isRunning = true; isRunning; ) {
          Thread.sleep(SLEEP_UNIT);
          try {
            result = process.exitValue();
            isRunning = false;
          }
          catch (IllegalThreadStateException ie) {}

          try {
            pipe(System.in, process.getOutputStream(), false);
            pipe(process.getErrorStream(), System.err, false);
            pipe(process.getInputStream(), System.out, false);
          }
          catch (Exception e) {}
        }
        System.exit(result);
      }
    }
    catch (Exception e) {
      System.err.println(e);
    }
  }

  static void pipe(InputStream in, OutputStream out, boolean isBlocking) throws
      IOException {
    int nread;
    int navailable;
    int total = 0;
    synchronized (in) {
      while ( (navailable = isBlocking ? Integer.MAX_VALUE : in.available()) >
             0 &&
             (nread = in.read(buf, 0, Math.min(buf.length, navailable))) >= 0) {
        out.write(buf, 0, nread);
        total += nread;
      }
    }
    out.flush();
  }
}